package fragment;


import java.util.Vector;

import message.Message;
import message.MessageRelease;
import message.MessageStimulation;
import message.MessageStopStimulation;

import utils.Debug;
import visualisation.CompositionView;

public class Behavior extends QuasiComponentBehavior{
	
	private static boolean debugAgent = false;

	private AgentState currentState=AgentState.UNSATISFIED;
	private AgentState precedentState=AgentState.UNSATISFIED;
	
	private boolean stimChanged;
	
	
	
	private void perception(){
		Vector<Message> messages=architecture().receive();
		
		if(messages.size()!=0 && debugAgent) Debug.println("Agent "+this.architecture().getId()+" received "+messages.size()+" messages");
		
				
		stimChanged=false;
		
		for(Message m : messages){
			switch(m.messageType){
				case RELEASE :
					this.architecture().release(((MessageRelease)m).mmme);
					break;
				case STIMULATION :
					stimChanged=true;
					this.architecture().updateReceivedStimulation((((MessageStimulation)m).sender),(((MessageStimulation)m).value)) ;
					break;
				case STOPSTIMULATION :
					stimChanged=true;
					this.architecture().cancelStimulation(((MessageStopStimulation)m).sender);
					break;
				default : Debug.println("Agent "+this.architecture().getId()+" received unknow message");
			}
		}
	}
	
	
	
	private boolean neededByNobody(){
		boolean res = true;
		for(String mmme : architecture().getGenerationCapabilities())
			if( ! architecture().nobodyNeed(mmme))res=false;
		return res;
	}
	
	
	
	private boolean isUseless(){
		
		//special case :  some fragments do not contribute to the meta-model (but are useful to the user)
		if (architecture().getGenerationCapabilities().isEmpty()) return false; 
		
		
		if(neededByNobody()) return true;
		
		if (currentState.equals(AgentState.SATISFIED)){
			boolean res=true;
			for(String s : architecture().getGenerationCapabilities()){
				if (! this.architecture().isMMMEGivenByUser(s)) 
					res=false;
			}
			return res;
		}
		else{
			boolean res=true;
			for(String s : architecture().getGenerationCapabilities()){
				if (! this.architecture().isElementPresent(s));
					res=false;
			}
			return res;
		}
	}
	
	private boolean cannotSatisfyPreconditions(){
		boolean res=false;
		
		for(String s : architecture().requiredElements()){
			if ( (!(architecture().isMMMEGivenByUser(s))
					&& (architecture().findAllPotentialGenerators(s).isEmpty())))
				res=true;
		}
		
		return res;
	}
	
	
	
	private void decision(){
			if (isUseless() || cannotSatisfyPreconditions()){
				precedentState=currentState;
				currentState=AgentState.INACTIVE;
				
				/**/
				if(debugAgent){
					if(isUseless())
						Debug.println("Agent "+this.architecture().getId()+" state : INACTIVE (useless)");
					else
						Debug.println("Agent "+this.architecture().getId()+" state : INACTIVE (cannot satisfy)");
				}
				
			}
			else if (architecture().allNeededElementReserved()){
				precedentState=currentState;
				currentState=AgentState.SATISFIED;
				
				/**/
				if(debugAgent) Debug.println("Agent "+this.architecture().getId()+" state : SATISFIED");
			}
			else{
				precedentState=currentState;
				currentState=AgentState.UNSATISFIED;
				
				/**/
				if(debugAgent) Debug.println("Agent "+this.architecture().getId()+" state : UNSATISFIED");
			}
	}
	
	private void action(){
	
		switch (currentState){

			case INACTIVE :
				if (!precedentState.equals(currentState)){
					switch (precedentState){
						case SATISFIED :
							architecture().stopGenerating();
						default : 
							architecture().releaseAll();
							architecture().stopStimulateAll();
							break;
					}
				}
				break;
			
			case UNSATISFIED :
				if (!precedentState.equals(currentState) && precedentState.equals(AgentState.SATISFIED))
							architecture().stopGenerating();
				
				if(stimChanged)this.architecture().updateAllStimulation();
				
				for(String s : architecture().requiredElements()){
		
					for(Fragment f : architecture().findAllPotentialGenerators(s))
						architecture().updateSendStimulation(f.getId(), architecture().getCurrentStimulation());
					if(architecture().isElementPresent(s))
						architecture().reserve(s);

				}
				break;
				
			case SATISFIED :	
				if(stimChanged)this.architecture().updateAllStimulation();
				
				if (!precedentState.equals(currentState))
					architecture().generate();
				break;
		}
		
		if(!precedentState.equals(currentState))	//update the GUI
			CompositionView.changeState(this.architecture().getId(), currentState);
		
		this.architecture().updateProcess();
	}
	
	@Override
	public void step() {
		
		if (debugAgent) Debug.println("Agent "+this.architecture().getId()+" start new cycle");
		
		perception();
		decision();
		action();
		
		if (debugAgent) Debug.println("Agent "+this.architecture().getId()+" end cycle");
		
	}

	@Override
	public AgentState getState() {
		return currentState;
	}
	
	@Override
	public void start() {
		if (debugAgent) Debug.println("Agent "+this.architecture().getId()+" : started");
		
	}

	

}
